using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Styx.Combat.CombatRoutine;
using Styx.WoWInternals.WoWObjects;
using Styx.WoWInternals;
using Styx.Logic.Combat;
using Styx.Helpers;
using Styx.Logic.Pathing;
using Styx;
using Styx.Logic;
using System.Diagnostics;
using System.Net;
using System.Windows.Forms;



namespace Druidhealz
{
    public partial class Druidhealz : CombatRoutine
    {

        #region Settings
        // Health Settings, Defaults should be good, but if you want to tweak the hell out of them, go ahead
        // ====================================================
        int hpwg = 80;           // when to cast Wild Growth
        int hprj = 90;           // when to cast Rejuvenation - keep in mind that for levels 80+, it will ALWAYS keep rejuvenation on all party members
        int hprg = 70;           // when to cast Regrowth
        int hpht = 40;           // when to cast Healing Touch / Nourish. Nourish will replace Healing Touch when it becomes available
        int hplb = 50;           // allow Lifebloom to bloom when tank drops belows this percentage
        int hpsw = 70;           // when to Swiftmend a Rejuvenation
        int hptq = 45;           // when to Tranq
        // ====================================================
        int mebk = 70;           // when to use Barkskin on myself
        int memn = 50;           // when to use Innervate on myself
        // ====================================================
        string pullspell = "Faerie Fire";   // Quick Workaround. Faerie Fire or Insect Swarm.
        // ==================================================== 
        #endregion

        private static readonly Version pVersion = new Version("6");
        public override sealed string Name { get { return "Druidhealz"; } }
        public override WoWClass Class { get { return WoWClass.Druid; } }
        private static LocalPlayer Me { get { return ObjectManager.Me; } }

        private WoWUnit lastCast;
        private WoWUnit tank;
        private Random rng;

        public override void Initialize()
        {
            string versionURL = "http://druidhealz.googlecode.com/svn/trunk/Druidhealz/version.txt";
            WebClient client = new WebClient();
            string UpToDateVersion = null;

            try
            {
                UpToDateVersion = client.DownloadString(versionURL);
            }
            catch
            {
            }

            if (UpToDateVersion != null && UpToDateVersion != pVersion.ToString())
            {
                MessageBox.Show("There is a new version for Druidhealz \r\n It is highly suggested to update!", "Druidhealz Update", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }
        public override void Pulse()
        {
            if (Me != null && Me.IsValid && Me.IsAlive && Me.IsInInstance)
            {
                tank = GetTank();
                if (tank == null)
                {
                    tank = Me;
                }
                Combat();
            }
        }

        public override void Combat()
        {
            if (StyxWoW.GlobalCooldown)
                return;
            else if (CombatRes())
                return;
            else if (CancelHeal())
                return;
            else if (GroupHeal())
                return;
            else if (Self())
                return;
            else if (Healing())
                return;
            else if (Cleansing())
                return;
            else if (Swarm())
                return;
            else if (Buff())
                return;
        }

        private bool Swarm()
        {
            WoWUnit u = (from unit in ObjectManager.GetObjectsOfType<WoWUnit>(false, false)
                         where unit.IsHostile
                         where !unit.Dead
                         where unit.CurrentTargetGuid == tank.Guid
                         where unit.Distance < 40
                         where unit.InLineOfSight
                         select unit
                        ).FirstOrDefault();
            if (u != null && !Me.Combat && CC(pullspell, u))
            {
                C(pullspell, u);
                return true;
            }

            return false;
        }


        private WoWPoint NextTo(WoWUnit u)
        {
            if (rng == null)
            {
                rng = new Random();
            }
            return WoWMathHelper.CalculatePointAtSide(u.Location, u.Rotation, rng.Next(10), rng.Next(2) == 1);
        }

        private bool CancelHeal()
        {
            if (Me.IsCasting && (lastCast != null && !lastCast.Dead && lastCast.HealthPercent >= 85))
            {
                Log("Cancelling cast " + lastCast);
                lastCast = null;
                SpellManager.StopCasting();
                return true;
            }
            else if (Me.IsCasting)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        private WoWPlayer GetTank()
        {
            if (RaFHelper.Leader != null)
                return RaFHelper.Leader;

            foreach (WoWPlayer p in Me.PartyMembers)
            {
                if (IsTank(p))
                {
                    return p;
                }
            }
            return null;
        }

        private string DeUnicodify(string s)
        {

            StringBuilder sb = new StringBuilder();
            byte[] bytes = Encoding.UTF8.GetBytes(s);
            foreach (byte b in bytes)
            {
                if (b != 0)
                    sb.Append("\\" + b);
            }
            return sb.ToString();
        }

        private bool IsTank(WoWPlayer p)
        {
            return Lua.GetReturnValues("return UnitGroupRolesAssigned('" + DeUnicodify(p.Name) + "')").First() == "TANK";
        }

        private bool CombatRes()
        {
            // Don't run the code in Raids and BattleGrounds - not ready for this!
            if (Me.IsInRaid || Battlegrounds.IsInsideBattleground) 
                return false;
                
            WoWPlayer p = GetTank();
            
            if (p != null && p.Dead && !p.IsMe)
            {
                if (p.Distance > 40 || !p.InLineOfSight)
                {
                    Log("moving to rebirth " + p);
                    MoveTo(p);
                    return true;
                }
                else if (p.Dead && !p.IsMe && CC("Rebirth", p))
                {
                    return C("Rebirth", p);
                }
                else
                {
                    return false;
                }
            }
            return false;
        }

        private bool Self()
        {
            if (NeedsCleanse(Me) && Me.ManaPercent > 70 && Me.HealthPercent > 70) {
                C("Remove Corruption");
                return true;
            }
            else if (CC("Nature's Grasp") && Me.HealthPercent < 70 && !isAuraActive("Nature's Grasp"))
            {
                WoWPlayer p = GetClosePlayer(8);
                if (p != null)
                {
                    MoveTo(p);
                }
                Log("Running to " + p);
                C("Nature's Grasp");
                return true;    
            }
            else if (!isAuraActive("Barkskin", Me) && Me.HealthPercent < mebk && CC("Barkskin"))
            {
                C("Barkskin");
                return true;
            }
            else if (Me.ManaPercent <= memn && CC("Innervate"))
            {
                C("Innervate");
                return true;
            }
            else
            {
                return false;
            }
        }
        
        private bool GroupHeal()
        {
            int wgcandidate = 0;
            int tranqcanditate = 0;
            
            foreach (WoWPlayer p in (Me.IsInRaid ? Me.RaidMembers : Me.PartyMembers))
            {
                if (p.HealthPercent < hpwg && p.HealthPercent > hptq && p.Distance < 20)
                {
                    wgcandidate++;
                }
                else if (p.HealthPercent <= hptq && p.Distance < 35)
                {
                    tranqcanditate++;
                }
                
                if (CC("Wild Growth") && ((wgcandidate >= 3 && !Me.IsInRaid) || (wgcandidate >= 5 && Me.IsInRaid)))
                {
                    Log(wgcandidate + " party members are below " + hpwg + "%!");
                    return C("Wild Growth",p);
                }
                else if (CC("Tranquility") && ((tranqcanditate >= 3 && !Me.IsInRaid) || (tranqcanditate >= 5 && Me.IsInRaid))) {
                    WoWMovement.MoveStop();
                    Log(tranqcanditate + " party members are below " + hptq + "%!");
                    return C("Tranquility");
                }
                return false;
            }
            return false;
        }
        

        private bool CC(string spell, WoWUnit target)
        {
            return SpellManager.CanCast(spell, target);
        }

        private bool CC(string spell)
        {
            return SpellManager.CanCast(spell);
        }

        private void ChainSpells(params string[] spells)
        {
            string macro = "";
            foreach (string s in spells)
            {
                macro += "CastSpellByName(\"" + s + "\", true);";
            }
            Lua.DoString(macro);
        }

        private bool Cleansing()
        {
            WoWPlayer p = GetCleanseTarget();
            if (p != null)
            {
                if (p.Distance > 40 || !p.InLineOfSight)
                {
                    MoveTo(p);
                    return true;
                }
                else if (CC("Remove Corruption", p))
                {
                    C("Remove Corruption", p);
                    return true;
                }
                else
                {
                    Log("no Remove Corruption " + p);
                    return false;
                }
            }
            else
            {
                return false;
            }
        }

        private WoWPlayer GetCleanseTarget()
        {
            return (from unit in ObjectManager.GetObjectsOfType<WoWPlayer>(true, true)
                    orderby unit.HealthPercent ascending
                    where !unit.Dead
                    where !unit.IsGhost
                    where unit.IsFriendly
                    where unit.Distance < 80
                    where NeedsCleanse(unit)
                    select unit).FirstOrDefault();
        }

        private bool NeedsCleanse(WoWPlayer p)
        {
            foreach (WoWAura a in p.ActiveAuras.Values)
            {
                if (a.IsHarmful && Me.ManaPercent > 75)
                {
                    WoWDispelType t = a.Spell.DispelType;
                    if (t == WoWDispelType.Curse || t == WoWDispelType.Magic || t == WoWDispelType.Poison)
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        private WoWPlayer GetHealTarget()
        {
            return (from unit in ObjectManager.GetObjectsOfType<WoWPlayer>(true, true)
                    orderby unit.HealthPercent ascending
                    where !unit.Dead
                    where !unit.IsGhost
                    where  unit.IsFriendly
                    where unit.Distance < 80
                    where unit.HealthPercent < 99
                    select unit).FirstOrDefault();
        }

        private WoWPlayer GetClosePlayer(int range) 
        {
            return (from unit in ObjectManager.GetObjectsOfType<WoWPlayer>(true, true)
                    orderby unit.Distance ascending
                    where !unit.Dead
                    where !unit.IsGhost
                    where  unit.IsFriendly
                    where unit.Distance > range
                    select unit).FirstOrDefault();            
        }
        
        private IEnumerable<WoWPlayer> GetResurrectTargets()
        {
            return (from unit in ObjectManager.GetObjectsOfType<WoWPlayer>(false, false)
                    orderby unit.Distance ascending
                    where unit.Dead
                    where unit.IsInMyPartyOrRaid
                    where !unit.IsGhost
                    where unit.Distance < 100
                    select unit);
        }

        private bool Resurrecting()
        {
            if (Battlegrounds.IsInsideBattleground) 
                return false;
               
            foreach (WoWPlayer p in GetResurrectTargets())
            {
                if (Blacklist.Contains(p.Guid, true))
                {
                    continue;
                }
                else
                {
                    if (p.Distance > 40 || !p.InLineOfSight)
                    {
                        Log("moving to res " + p);
                        MoveTo(p);
                        return true;
                    }
                    else if (CC("Revive", p) && C("Revive", p))
                    {
                        Log("added " + p + " to res blacklist for 15s");
                        Blacklist.Add(p, new TimeSpan(0, 0, 15));
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
            }
            return false;
        }

        private bool Buff()
        {
            if (Resurrecting())
            {
                return true;
            }
            if (!isAuraActive("Mark of the Wild"))
            {
                C("Mark of the Wild");
                return true;
            }
            foreach (WoWPlayer p in Me.PartyMembers)
            {
                if (p.Distance > 40 || p.Dead || p.IsGhost)
                    continue;
                else if (!isAuraActive("Blessing of Kings", p) && !isAuraActive("Mark of the Wild", p))
                {
                    C("Mark of the Wild", p);
                    return true;
                }
            }
            return false;
        }

        private bool isAuraActive(string name)
        {
            return isAuraActive(name, Me);
        }

        private bool isAuraActive(string name, WoWUnit u)
        {
            return u.ActiveAuras.ContainsKey(name);
        }

        public override bool NeedRest
        {
            get
            {

                if (Me.ManaPercent < 30 &&
                    !Me.Auras.ContainsKey("Drink")) //To prevent food spam.
                {
                    Log("Need Drink");
                    return true;
                }

                return false;
            }
        }

        public override void Rest()
        {
            // this ought never get run over level 3
            if (Me.ManaPercent < 50)
            {
                Styx.Logic.Common.Rest.Feed(); //these arent needed.
            }

        }

        public override bool NeedPullBuffs { get { Pulse(); return false; } }

        public override bool NeedCombatBuffs { get { Pulse(); return false; } }

        public override bool NeedPreCombatBuffs { get { Pulse(); return false; } }

    }
}